package org.ccay.async.impl;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import org.ccay.async.AsyncMessage;
import org.ccay.async.IAsyncFramework;
import org.ccay.async.IMessageProcessor;
import org.ccay.async.conduit.AsyncConduit;
import org.ccay.async.config.AsyncConduitConfig;
import org.ccay.async.config.MessageProcessorConfig;
import org.ccay.async.processor.ContextAwareProcessor;
import org.ccay.async.processor.ThreadNameInterceptProcessor;
import org.ccay.core.exception.ApplicationException;
import org.ccay.core.log.ILogger;
import org.ccay.core.log.CcayLoggerFactory;

/**
 * AsyncFramework的实现
 */
@Named
public class AsyncFramework implements IAsyncFramework, InitializingBean, ApplicationListener<ApplicationEvent> {
	
	/** 日志记录器 **/
	private final ILogger logger = CcayLoggerFactory.getLogger(IAsyncFramework.class);
	
	/** 异步通道配置列表, key: 消息的类型 **/
	private Map<String, AsyncConduitConfig> conduitsConfig = new HashMap<String, AsyncConduitConfig>();
	
	/** 消息处理器配置列表, key: 消息的类型 **/
	private Map<String, MessageProcessorConfig> processorsConfig;
	
	/** AsyncFramework实例 **/
	private static IAsyncFramework instance;
	
	@Inject
	@Named("defaultConduit")
	private AsyncConduit defualtConduit;
	
	public void setDefualtConduit(AsyncConduit defualtConduit) {
		this.defualtConduit = defualtConduit;
	}

	/**
	 * 获取AsyncFramework实例
	 */
	public static IAsyncFramework getInstance() {
		return instance;
	}
	
	public void afterPropertiesSet() throws ApplicationException {
		instance = this;
		
		if(this.defualtConduit == null) {
			logger.warn("Can't find default conduit config which named 'defaultConduit' for Async Framework.");
		}
	}
	
	/**
	 * 收集系统中注册的异步通道。
	 * 	
	 * 
	 * @since Dec 13, 2011
	 */
	private void collectConduitConfig(ApplicationContext applicationContext) {
		Map<String, AsyncConduitConfig> conduitConfigs = applicationContext.getBeansOfType(AsyncConduitConfig.class);
		Iterator<AsyncConduitConfig> iter = conduitConfigs.values().iterator();
		while(iter.hasNext()) {
			AsyncConduitConfig msgConfig = iter.next();
			if(conduitsConfig.containsKey(msgConfig.getMessageType())) {
				logger.warn("Duplicated async conduit config for message: "+msgConfig.getMessageType());
			} else {
				conduitsConfig.put(msgConfig.getMessageType(), msgConfig);
			}
		}
	}
	
	/**
	 * 收集系统中注册的消息处理器。
	 */
	private void collectProcessorConfig(ApplicationContext applicationContext) {
		
		// begin modify by zwx304259 SP20  增加非空判断,解决CCM项目引用jar包问题
		if (null == processorsConfig) {
			this.processorsConfig = new HashMap<String, MessageProcessorConfig>();
		}
		// end modify by zwx304259
		
		Map<String, MessageProcessorConfig> processorConfigs = applicationContext.getBeansOfType(MessageProcessorConfig.class);
		Iterator<MessageProcessorConfig> iter = processorConfigs.values().iterator();
		while(iter.hasNext()) {
			MessageProcessorConfig msgConfig = iter.next();
			if(processorsConfig.containsKey(msgConfig.getMessageType())) {
				logger.warn("Duplicated message processor config for message: "+msgConfig.getMessageType());
			} else {
				IMessageProcessor processor = msgConfig.getProcessor();
				if(msgConfig.isContextAware()) {
					// 根据contextAware的属性，对消息处理器进行上下文装饰
					processor = new ContextAwareProcessor(msgConfig.getProcessor());
				}
				//线程名装饰器
				processor = new ThreadNameInterceptProcessor(processor);
				msgConfig.setProcessor(processor);
				processorsConfig.put(msgConfig.getMessageType(), msgConfig);
			}
		}
	}
	
	/**
	 * 根据消息获取该消息配置的异步通道。
	 * @param message
	 * @return
	 */
	public AsyncConduitConfig getConduitConfig(AsyncMessage message) {
		return getConduits(message.getType());
	}
	
	/**
	 * 根据消息获取该消息配置的异步通道。
	 * @return
	 */
	public AsyncConduitConfig getConduits(String messageType) {
		if(conduitsConfig.containsKey(messageType)) {
			return conduitsConfig.get(messageType);
		}
		
		return null;
	}
	
	/**
	 * 根据消息获取该消息的业务处理器。
	 * @return
	 */
	public IMessageProcessor getMessageProcessor(AsyncMessage message) {
		return getMessageProcessor(message.getType());
	}
	
	/**
	 * 根据消息获取该消息的业务处理器。
	 * @return
	 */
	public IMessageProcessor getMessageProcessor(String messageType) {
		logger.info("Ready to process async message of [{0}] ",messageType);
		if(null != processorsConfig && processorsConfig.containsKey(messageType)) {
			return processorsConfig.get(messageType).getProcessor();
		}
		logger.error("Async message of [{0}] has no registed processor.",messageType);
		return null;
	}

	public void onApplicationEvent(ApplicationEvent event) {
		if(event instanceof ContextRefreshedEvent) {
			ApplicationContext applicationContext = ((ContextRefreshedEvent)event).getApplicationContext();
			this.collectConduitConfig(applicationContext);
			this.collectProcessorConfig(applicationContext);
		}
	}

	public AsyncConduit getDefaultConduit() {
		return this.defualtConduit;
	}

}
